package ordersubmit

import (
	"fmt"
	"sort"
	"strconv"
	"strings"

	"mall/common/globalkey"
	"mall/common/moneyx"
	"mall/common/utils/pointy"
	"mall/service/forum/api/internal/biz/promotion"
	"mall/service/forum/api/internal/types"
	"mall/service/product/rpc/productclient"
	"mall/service/promotion/rpc/promotionclient"

	"github.com/shopspring/decimal"
	"github.com/sirupsen/logrus"
	"github.com/zeromicro/go-zero/core/logx"
)

// SkuInfoHandler 商品信息handler
type SkuInfoHandler struct {
	// 合成复用Next
	Next
}

// Do 商品信息逻辑
func (h *SkuInfoHandler) Do(c *Context) (err error) {
	// logx.Infow("获取商品信息...")

	limit := uint32(len(c.Req.Skus))
	if limit == 0 {
		return
	}

	skuIdMap := make(map[uint64][]*types.ShoppingCartItemInfo)
	var variationIds []string
	for _, v := range c.Req.Skus {
		logrus.Info(fmt.Sprintf("SkuInfoHandler sku: %+v", v))
		// &{SkuId:0xc000a706d8 SkuCode:<nil> Quantity:0xc000a7074c Selected:<nil> PostId:<nil> InviterId:<nil> Id:<nil> ShopId:<nil> ProductId:<nil> ProductCode:<nil> ProductType:<nil> EntryId:<nil> OrderId:<nil> RetailPrice:<nil> Inventory:<nil> Weight:<nil> Title:<nil> Slug:<nil> BrandId:<nil> BrandTitle:<nil> BrandSlug:<nil> MediaId:<nil> MediaUrl:<nil> Status:<nil> Favorable:<nil> Prefetched:<nil> Memo:<nil> CreatedAt:<nil> UpdatedAt:<nil> SkuAmount:<nil> ActivityAmount:<nil> CouponAmount:<nil> DiscountAmount:<nil> FinalAmount:<nil> ExchangeLogIds:[1] ExchangeGoodsId:<nil> ExchangePoint:<nil> Categories:[] Type:<nil> Sku:<nil> Addition:<nil> ExtJsonStr:<nil> GoodsTimesDay:<nil> GoodsTimesItem:<nil> WholesaleId:<nil>}
		// &{SkuId:0xc000a71310 SkuCode:<nil> Quantity:0xc000a7134c Selected:<nil> PostId:<nil> InviterId:<nil> Id:<nil> ShopId:<nil> ProductId:<nil> ProductCode:<nil> ProductType:<nil> EntryId:<nil> OrderId:<nil> RetailPrice:<nil> Inventory:<nil> Weight:<nil> Title:<nil> Slug:<nil> BrandId:<nil> BrandTitle:<nil> BrandSlug:<nil> MediaId:<nil> MediaUrl:<nil> Status:<nil> Favorable:<nil> Prefetched:<nil> Memo:<nil> CreatedAt:<nil> UpdatedAt:<nil> SkuAmount:<nil> ActivityAmount:<nil> CouponAmount:<nil> DiscountAmount:<nil> FinalAmount:<nil> ExchangeLogIds:[] ExchangeGoodsId:0xc000a716a8 ExchangePoint:<nil> Categories:[] Type:<nil> Sku:<nil> Addition:<nil> ExtJsonStr:<nil> GoodsTimesDay:<nil> GoodsTimesItem:<nil> WholesaleId:<nil>}
		if v.SkuId != nil && v.Quantity != nil && *v.SkuId > 0 && *v.Quantity > 0 {
			skuIdMap[*v.SkuId] = append(skuIdMap[*v.SkuId], v)
			variationIds = append(variationIds, strconv.FormatUint(*v.SkuId, 10))
		}
	}
	if len(variationIds) == 0 {
		return
	}

	preload := "product:Id,ParentId,Title,Slug"
	eagerLoad := "product:productMeta,productRelationship,productTerm,productVariation,productVariationMeta"
	preFilter := "Id,in:" + strings.Join(variationIds, ",")
	preFilterEntity := "productVariation"
	preFilter += ";Status,equalTo:" + strconv.FormatInt(int64(globalkey.StatusEnabled), 10)
	// preload += ";productMedia:Id,Uid,Url,Thumbnail,Order"
	preload += ";productRelationship:PerfumeId,PerfumeName,PerfumeSlug,BrandId,BrandName,BrandSlug"
	preload += ";productTerm:Id,Name,Slug,ParentId"
	preload += ";productMeta:mediaId,mediaUrl,gemPriceMin,gemPriceMax"
	preload += ";productVariation:Id,GemPrice,RetailPrice,CounterPrice,Weight,SkuType"
	preload += ";productVariationMeta:stock,mediaId,mediaUrl,sku,skuKey"
	res, err := c.SvcCtx.ProductRpc.GetProductList(c.Ctx, &productclient.BaseListReq{
		Limit:           limit,
		Preload:         pointy.GetPointer(preload),
		EagerLoad:       pointy.GetPointer(eagerLoad),
		PreFilterEntity: pointy.GetPointer(preFilterEntity),
		PreFilter:       pointy.GetPointer(preFilter),
	})
	if err != nil {
		return err
	}

	// logx.Infow("商品库存校验...")
	if len(res.List) > 0 {
		var total int64 // 总件数
		// var gems int64              // 宝石
		var point string            // 积分
		isValid := true             // 库存有效
		var fAmount decimal.Decimal // 人民币
		var fWeight decimal.Decimal // 总重
		for _, item := range res.List {
			if len(item.Skus) > 0 {
				var brandId *uint64
				var brandTitle *string
				var brandSlug *string
				var entryId *uint64
				if len(item.Relations) > 0 {
					for _, v := range item.Relations {
						if v.Key != nil {
							switch *v.Key {
							case globalkey.ProductRelationNameBrand:
								brandId = v.Id
								brandTitle = v.Name
								brandSlug = v.Slug
							case globalkey.ProductRelationNamePerfume:
								entryId = v.Id
							}
						}
					}
				}

				var itemMediaId *string
				var itemMediaUrl *string
				var gemPriceMin string
				var gemPriceMax string
				if len(item.Meta) > 0 {
					for _, m := range item.Meta {
						if m.Key == nil || m.Value == nil {
							continue
						}

						val := *m.Value
						switch *m.Key {
						case "gemPriceMin":
							gemPriceMin = val
						case "gemPriceMax":
							gemPriceMax = val
						case "mediaId":
							itemMediaId = pointy.GetPointer(val)
						case "mediaUrl":
							itemMediaUrl = pointy.GetPointer(val)
						}
					}
				}

				if gemPriceMin != gemPriceMax { // Todo: 暂时限制，不允许试香有多个规格（也就不会有多个兑换积分）
					gemPriceMin = ""
				}

				if len(item.Media) > 0 {
					for _, v := range item.Media {
						var url string
						if v.Url != nil && len(*v.Url) > 0 {
							url = *v.Url
						}
						if len(url) == 0 && v.Uri != nil && len(*v.Uri) > 0 {
							url = *v.Uri
						}
						if len(url) > 0 {
							itemMediaId = v.Id
							itemMediaUrl = pointy.GetPointer(url)
							break
						}
					}
				}

				var categories []*types.CategoryInfo
				var categoryIds []uint64
				if len(item.Categories) > 0 {
					for _, v := range item.Categories {
						categories = append(categories, &types.CategoryInfo{
							Id:       v.Id,
							Name:     v.Name,
							Slug:     v.Slug,
							ParentId: v.ParentId,
						})
						if v.Id != nil && *v.Id > 0 {
							categoryIds = append(categoryIds, *v.Id)
						}
					}
				}
				for _, sku := range item.Skus {
					if sku.Id == nil {
						continue
					}

					// logrus.Info(fmt.Sprintf("SkuInfoHandler sku: %+v", sku))
					// Id:142 Key:"135" GemPrice:"1000" RetailPrice:"8" CounterPrice:"10" Weight:"0" SkuCode:"669632558" SkuType:0 Status:1 SaleCount:0 Label:"3-容轾-Volumn:0-1ml-"
					if reqSkus, ok := skuIdMap[*sku.Id]; ok {
						var number uint32                // 总数
						for _, reqSku := range reqSkus { // 可能出现多次（已兑、随手兑一件）
							if reqSku.Quantity != nil && *reqSku.Quantity > 0 {
								number += *reqSku.Quantity
							}
						}
						total += int64(number)

						var status int32
						var mediaId *string
						var mediaUrl *string
						pricingInfo := &promotion.PricingInfo{
							SkuId:     *sku.Id,
							ProductId: *item.Id,
						}
						var isExchangeItem bool
						var skuType *uint32
						for idx, reqSku := range reqSkus {
							var reqNumber int64
							if reqSku.Quantity != nil && *reqSku.Quantity > 0 {
								reqNumber = int64(*reqSku.Quantity)
							}
							if idx == 0 { // 只在第一次循环，决定order item的状态、缩略图等
								if c.OrderType == globalkey.OrderTypeVirtual {
									if sku.SkuType != nil && *sku.SkuType == globalkey.ProductTypeVirtual {
										status = globalkey.StatusEnabled
										skuType = sku.SkuType
									} else {
										status = globalkey.StatusWrongType
										isValid = false
									}
								} else {
									if sku.Inventory != nil && number > *sku.Inventory {
										status = globalkey.StatusOverSize
										isValid = false
									} else {
										status = globalkey.StatusEnabled
										skuType = pointy.GetPointer(globalkey.ProductTypeCommon)
									}
								}
								pricingInfo.Status = status

								if sku.MediaId != nil && len(*sku.MediaId) > 0 {
									mediaId = sku.MediaId
								} else {
									mediaId = itemMediaId
								}

								if sku.MediaUrl != nil && len(strings.TrimSpace(*sku.MediaUrl)) > 0 {
									mediaUrl = sku.MediaUrl
								} else {
									mediaUrl = itemMediaUrl
								}

								if len(reqSku.ExchangeLogIds) == 0 && reqSku.ExchangeGoodsId == nil {
									pricingInfo.SkuNumber += reqNumber
								} else {
									isExchangeItem = true
									skuType = pointy.GetPointer(globalkey.ProductTypeExchange)
									if reqSku.ExchangeGoodsId != nil && *reqSku.ExchangeGoodsId > 0 {
										point = gemPriceMin
									}
								}
							}

							if !isExchangeItem && sku.RetailPrice != nil && len(*sku.RetailPrice) > 0 {
								if _, ok := c.SkuAmountMap[*sku.Id]; !ok {
									fp, err := moneyx.ParseDecimal(*sku.RetailPrice)
									if err != nil {
										logx.Errorw("failed to ParseDecimal", logx.Field("detail", err.Error()),
											logx.Field("retailPrice", *sku.RetailPrice))
									} else {
										pricingInfo.SkuPrice = fp

										fa := fp.Mul(decimal.NewFromInt(reqNumber))
										c.SkuAmountMap[*sku.Id] = fa

										pricingInfo.SkuAmount = fa
										pricingInfo.FinalAmount = fa
										fAmount = fAmount.Add(fa)
									}
								}
							}

							if c.OrderType != globalkey.OrderTypeVirtual && sku.Weight != nil && len(*sku.Weight) > 0 {
								if weight, err := moneyx.ParseDecimal(*sku.Weight); err != nil {
									logx.Errorw("failed to ParseDecimal", logx.Field("detail", err.Error()),
										logx.Field("weight", *sku.Weight))
								} else {
									fWeight = fWeight.Add(weight.Mul(decimal.NewFromInt(reqNumber)))
								}
							}
							c.Resp.List = append(c.Resp.List, &types.ShoppingCartItemInfo{
								ShopId:          pointy.GetPointer(uint64(1)),
								SkuId:           sku.Id,
								SkuCode:         sku.SkuCode,
								ProductId:       item.Id,
								ProductCode:     item.ProductCode,
								ProductType:     skuType,
								EntryId:         entryId,
								RetailPrice:     sku.RetailPrice,
								Quantity:        reqSku.Quantity,
								Inventory:       sku.Inventory,
								Weight:          sku.Weight,
								Title:           item.Title,
								Slug:            item.Slug,
								BrandId:         brandId,
								BrandTitle:      brandTitle,
								BrandSlug:       brandSlug,
								MediaId:         mediaId,
								MediaUrl:        mediaUrl,
								Sku:             sku.Label,
								Status:          pointy.GetPointer(status),
								Categories:      categories,
								PostId:          reqSku.PostId,
								InviterId:       reqSku.InviterId,
								ExchangeLogIds:  reqSku.ExchangeLogIds,
								ExchangeGoodsId: reqSku.ExchangeGoodsId,
								ExchangePoint:   pointy.GetPointer(point),
							})

							c.SkuScopeInfos = append(c.SkuScopeInfos, &promotionclient.SkuScopeInfo{
								VariationId: sku.Id,
								ProductId:   item.Id,
								EntryId:     entryId,
								BrandId:     brandId,
								CategoryIds: categoryIds,
							})

							c.PricingInfos = append(c.PricingInfos, pricingInfo)
						}
					}
				}
			}
		}

		c.Resp.StockValid = isValid
		c.Resp.Total = pointy.GetPointer(uint32(total))
		c.Resp.Weight = pointy.GetPointer(moneyx.FormatDecimal(fWeight, 3))
		// c.Resp.GemAmount =
		// 	pointy.GetPointer(moneyx.FormatDecimal(fAmount.Mul(decimal.NewFromInt(int64(globalkey.GemRatio))), 2))
		c.Resp.RetailAmount = pointy.GetPointer(moneyx.FormatDecimal(fAmount, 2))
		c.SkusAmount = fAmount
		c.SkusNumber = total
		c.SkusWeight = fWeight
		c.FinalAmount = fAmount

		sort.Slice(c.PricingInfos, func(i, j int) bool {
			return c.PricingInfos[i].SkuPrice.GreaterThan(c.PricingInfos[j].SkuPrice)
		})
	}

	return
}
